//
//  main.m
//  C09_函数指针
//
//  Created by dllo on 15/11/27.
//  Copyright © 2015年 dllo. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "student.h"
typedef int ii;
typedef int (*FUN)(int, int);

int mulValue(int x, int y){
    return x*y;
}

/* 函数: 参数含有函数指针 */
int getValue(int, int, int (*)(int , int));
int getValue(int x, int y, int (*p)(int , int)){
    
    int value = p(x, y);
    return value;
}




/* 函数排序(数组版本) */
void PX(int array[], int count);
void PX(int array[], int count){
    int temp = 0;
    for (int i = 0; i < count - 1; i++) {
        for (int j = 0; j < count - 1 - i; j++) {
            if (array[j] > array[j + 1]) {
                temp = array[j];
                array[j] = array[j + 1];
                array[j + 1] = temp;
            }
        }
    }
    for(int i = 0; i < count; i++){
    printf("%d ", array[i]);
}

}
/*函数排序(指针版本)*/
void PX2(int * array, int count);
int temp = 0;
void PX2(int *array,int count);
void PX2(int *array,int count) {
    
    int temp = 0;
    for (int i = 0; i < count - 1; i++) {
        for (int j = 0; j < count - 1 - i; j++) {
            if (*(array + j) > *(array + j + 1)) {
                temp = *(array + j);
                *(array + j) = *(array + 1 + j);
                *(array + 1 + j) = temp;
            }
        }
    }
    
}
void ShuChu(int *array, int count);
void ShuChu(int *array, int count){
    for (int i = 0; i < count; i++) {
        printf("%d ", *(array + i));
    }
}









//void printHello();
//void printHello(){
//    printf("Hello\n");
//}

/* 声明一个求两个数最大值的函数 */
int maxValue(int x, int y);

int maxValue(int x, int y){
    return x > y ? x : y;
}
 /*返回两个整数的和*/
int sumValue  (int x, int y);
int sumValue  (int x, int y){
    return x + y;
}



int main(int argc, const char * argv[]) {
    
# pragma mark 知识点1 函数指针的定义与使用
    /* 函数指针: 指针指向函数(代码区) */
#if 0
    maxValue(3, 5);
    printf("max:%d\n", maxValue(3, 5));
    /* 查看代码区,查看maxValue函数的内存地址 */
    printf("max add:%p", maxValue);
    printf("sum add:%p", sumValue);
#endif
    /* !!! 重点: 如何确定函数指针类型
     *     技巧1: 函数声明部分 将函数名去掉就是韩数指针类型
     *     技巧2: 函数指针变量如何定义?
                  函数声明部分将函数名替换成(*p),其中的p是指针变量名
     */
//    int (*p)(int x, int y) = NULL;
    /* 上面语法说明:
     * 指针类型: int(*)(int x, int y)
     * 指针变量名: p
     * 指针变量值: NULL
     */
//    int *p2 = NULL; /* int a = 100; */


#if 0  /* 指针数组 数组指针  容易混淆的两个概念*/
    int * arr1[5] = {};/* 指针数组, 其中arr1 是数组名,5是数组元素个数, int* 是 数组中存放的指针的指针类型*/
    int (*arr)[5] = NULL;/* 数组指针, 其中arr 是指针的变量名,int * [5] 是指针类型
            arr +1, 访问下一个20个字节内容*/
    
    
    
#endif
#if 0
    /* 函数指针赋值 */
    int (*p)(int, int) = NULL;
    p = maxValue;/* 将指针指向了 maxValue函数代码的首地址.  注意: 指针类型和函数的类型要一致(包括返回值和参数列表)*/
    /* 通过 函数指针 调用函数 */
    p(3,5);
    printf("result:%d\n", p(3,5));
    p = sumValue;/* 将p指向sunValue函数代码首地址 */
    p(3,5);
    printf("result:%d\n", p(3,5));
#endif
# pragma mark 练习
#if 0
    /** (1). 定义可以指向系统strlen函数的指针 */
    size_t	 (*p)(const char *) = strlen;
    char string[] = "iphone";
    p(string);
    printf("%ld\n", p(string));
#endif
    /** (2). 定义一个指向系统strcpy函数的指针 */
#if 0
    char	*(*p)(char *, const char *) = strcpy;
    char string[] = "iphone";
    char string2[10] = {};
    p(string2,string);
    printf("%s\n", string2);
    
    
#endif
    
#if 0
    /** (3). 定义函数指针指向printHello函数. 并用函数指针调用函数 */
    void (*p)() = NULL;/* 定义一个指针变量 */
    p = printHello;/* 变量赋值 */
    p();/* 通过函数指针调用函数 */
#endif
    
    /** (4). 定义函数指针调用排序函数 */
    /* 定义一个函数指针,调用遍历输出数组的函数 */
#if 0
    void (*p)(int *, int) = NULL;
    p = PX2;/* 指针指向排序函数 */
    int array[4] = {2, 6, 4, 1};
    p(array,4);/* 调用 */
    p = ShuChu;/* 指针指向输出数组函数 */
    p(array,4);/* 调用 */
#endif
    /** (5). 定义两个 函数 ,一个求 最大值,一个 求和,输入maxValue或sumValue分别求 3 , 5的最大值或和
     
     * (提示,定义一个 函数指针 ,根据输入内容指向不同函数,最后一次调用完成)。*/
#if 0
    /* 定义字符串用于接收控制台输入的字符串 */
    char string[20] = "";
    printf("请输入字符串(maxValue或者sunValue)");
    scanf("%s", string);
    /* 定义一个指针 */
    int (*p)(int, int) = NULL;
    
    /* 根据不同的字符串,指针指向不同的函数 */
    if (strcmp(string, "macValue")==0) {
        p = maxValue;
    }else{
        printf("无效字符串\n");
    }
    /* 通过指针调用函数 输出结果 */
    if (p) {/*当指针不为空时*/
        printf("%d",p(3,5));
    }
    
#endif
    
    
# pragma mark 知识点2 函数回调(callback)
    /* 本质: 函数指针作为函数的参数 */
    
    /* 求两个数最大 */
    int max = getValue(3, 5, maxValue);
    printf("max:%d\n", max);
    /* 求两个数的和 */
    int sum = getValue(3, 5, sumValue);
    printf("sum:%d\n", sum);
    /* 求两个数的积 */
    int mul = getValue(3, 5, mulValue);
    printf("mul:%d\n", mul);
    
    
# pragma mark 练习
    /* (1) 写一函数查找成绩90分以上的学员,使用函数在姓名后加"高富帅" 
     *   使用同一函数,查找60分一下的学员,   使用回调函数使分数+5分
     */
    Student stu1 = {"zhang",20 , 89};
    Student stu2 = {"li", 19, 21};
    Student stu3 = {"wang", 20, 78};
    Student stu4 = {"wu", 20, 92};
    Student stu5 = {"bai", 19, 89};
    
    /* 定义一个结构体数组 */
    Student arrStu[5]={stu1, stu2, stu3, stu4, stu5};
    /* 调用查找学生函数*/
    selectedStudents(arrStu, 5, changeName);
    
    /* 调用遍历输出学生信息 */
    infoOfStudents(arrStu, 5);
    
    selectedStudents(arrStu, 5, changeScore);/* 此时在调用函数时,还是分数>90分的学生分数加5分,  因为selectedStudents函数内的判断条件是固定的,即( stu.score>90), 那么  如何使判断条件是动态变化的呢? 这就是下边动态排序的原理.详见  动态排序 */
    
# pragma mark 知识点3 动态排序
    
    
# pragma mark 练习
    
    
    /*按照姓名升序*/
    sortArr(arrStu, 5, cmpName);
    infoOfStudents(arrStu, 5);
    /* 按照分数升序排序 */
    sortArr(arrStu, 5, cmpScore);
    infoOfStudents(arrStu, 5);

    sortArr(arrStu, 5, cmpAge);
    infoOfStudents(arrStu, 5);

# pragma mark 知识点4 函数指针类型重定义(typedef)
    FUN point = maxValue;
    point(3, 5);
    printf("%d\n ", point(3, 5));
    
# pragma mark 练习
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    return 0;
}
